;
; x86cpu.asm - detect x86 family cpu features.
;
;
; sandpile on CPUID instruction:
;
; http://www.ee.nuigalway.ie/mirrors/www.sandpile.org/ia32/cpuid.htm 
;


segment .text



testCPUID:
        pushfd                          
        pop     eax
        mov     ecx,eax
        xor     eax,0x200000
        push    eax
        popfd
        pushfd
        pop     eax
        cmp     eax,ecx
        ret




;---------------------------------------
;       int  x86_compatible (void)
;---------------------------------------

%ifdef ELF_BINARY
 global x86_compatible
 x86_compatible:
%else
 global _x86_compatible
 _x86_compatible:
%endif
	; always true, ofcourse
	xor eax,eax
	inc eax
	ret



;---------------------------------------
;       int  x86_has_mmx (void)
;---------------------------------------

%ifdef ELF_BINARY
 global x86_has_mmx
 x86_has_mmx:
%else
 global _x86_has_mmx
 _x86_has_mmx:
%endif

        pushad
        call    testCPUID
        jz      return0         ; no CPUID command, so no MMX

        mov     eax,0x1
        cpuid
        test    edx,0x800000
        jz      return0         ; no MMX support
        jmp     return1         ; MMX support
        


;---------------------------------------
;       int  x86_has_sse (void)
;---------------------------------------

%ifdef ELF_BINARY
 global x86_has_sse
 x86_has_sse:
%else
 global _x86_has_sse
 _x86_has_sse:
%endif

        pushad
        call    testCPUID
        jz      return0         ; no CPUID command, so no SIMD
        
        mov     eax,0x1
        cpuid
        test    edx,0x02000000		; bit 25
        jz      return0         ; no SIMD support
        jmp     return1         ; SIMD support
        


;---------------------------------------
;       int  x86_has_sse2 (void)
;---------------------------------------

%ifdef ELF_BINARY
 global x86_has_sse2
 x86_has_sse2:
%else
 global _x86_has_sse2
 _x86_has_sse2:
%endif

        pushad
        call    testCPUID
        jz      return0         ; no CPUID command, so no SIMD2
        
	mov	eax,0x1
	cpuid
	test	edx,0x04000000		; bit 26
	jz	return0		; no SIMD2 support
	jmp	return1		; SIMD2 support



;---------------------------------------
;       int  x86_has_sse3 (void)
;---------------------------------------

%ifdef ELF_BINARY
 global x86_has_sse3
 x86_has_sse3:
%else
 global _x86_has_sse3
 _x86_has_sse3:
%endif

        pushad
        call    testCPUID
        jz      return0			; no CPUID command
        
	mov	eax,0x1
	cpuid
	test	ecx,1			; bit 0
	jz	return0			; no support
	jmp	return1			; supported




;---------------------------------------
; return int value (for all these functions)
;

return2:
	popad
	xor	eax,eax
	inc	eax
	inc	eax
	ret

return1:
	popad
	xor	eax,eax
	inc	eax
	ret

return0:
	popad
	xor	eax,eax
	ret



        
;---------------------------------------
;       int  x86_has_htt (void)
;---------------------------------------

%ifdef ELF_BINARY
 global x86_has_htt
 x86_has_htt:
%else
 global _x86_has_htt
 _x86_has_htt:
%endif

        pushad
        call    testCPUID
        jz      return0			; no CPUID command
        
	mov	eax,0x1
	cpuid
	test	edx,0x10000000		; bit 28
	jz	return0			; no HTT support
	jmp	return1			; HTT support

        


;---------------------------------------
;       int  x86_has_amd64 (void)
;---------------------------------------

%ifdef ELF_BINARY
 global x86_has_amd64
 x86_has_amd64:
%else
 global _x86_has_amd64
 _x86_has_amd64:
%endif

        pushad
        call    testCPUID
        jz      return0			; no CPUID command
        
	mov	eax,0x80000001
	cpuid
	test	edx,0x20000000		; bit 29
	jz	return0			; no AMD64 support
	jmp	return1			; AMD64 support



;---------------------------------------
;       int  x86_has_3dnow (void)
;---------------------------------------

%ifdef ELF_BINARY
 global x86_has_3dnow
 x86_has_3dnow:
%else
 global _x86_has_3dnow
 _x86_has_3dnow:
%endif

        pushad
        call    testCPUID
        jz      return0         ; no CPUID command, so no 3DNow!

	mov	eax,0x80000000
	cpuid
	cmp	eax,0x80000000
	jbe	return0		; no extended MSR(1), so no 3DNow!

	mov	eax,0x80000001
	cpuid

	test	edx,0x80000000
	jz	return0		; no 3DNow! support
				; 3DNow! support

	test	edx,0x40000000
	jz	return1		; no 3dnow_extended support
	jmp	return2		; 3dnow ext support




;---------------------------------------
;       int  x86_has_multicore (void)
;---------------------------------------

%ifdef ELF_BINARY
 global x86_has_multicore
 x86_has_multicore:
%else
 global _x86_has_multicore
 _x86_has_mutlicore:
%endif

        pushad
        call    testCPUID
        jz      return0			; no CPUID command

	xor	eax,eax
	cpuid
	cmp	eax,4
	jl	return0			; not supported

	mov	eax,4
	cpuid
	and	eax,0xFC000000
	shr	eax,26
	test	eax,0
	je	return0
	jmp	return1



;---------------------------------------
;       int  x86_has_multicore_numcores (void)
;---------------------------------------

	segment .data
tmp:	dd	0
	segment .text

%ifdef ELF_BINARY
 global x86_has_multicore_numcores
 x86_has_multicore_numcores:
%else
 global _x86_has_multicore_numcores
 _x86_has_multicore_numcores:
%endif

        pushad
        call    testCPUID
        jz      return0			; no CPUID command

	mov	eax,0
	cpuid	
	cmp	eax,4
	jl	return0			; no multicore
	mov	eax,4
	cpuid
	and	eax,0xFC000000
	shr	eax,26
	add	eax,1
	mov	[tmp],eax
	popad
	mov	eax,[tmp]
	ret



;---------------------------------------
;       int  x86_has_htt_numlogical (void)
;---------------------------------------

%ifdef ELF_BINARY
 global x86_has_htt_numlogical
 x86_has_htt_numlogical:
%else
 global _x86_has_htt_numlogical
 _x86_has_htt_numlogical:
%endif

        pushad
        call    testCPUID
        jz      return0			; no CPUID command

	mov	eax,1
	cpuid
	and	ebx,0x00FF0000
	shr	ebx,16
	mov	[tmp],ebx
	popad
	mov	eax,[tmp]
	ret


;---------------------------------------
;       int  x86_has_htt_apic_id (void)
;---------------------------------------

%ifdef ELF_BINARY
 global x86_has_htt_apic_id
 x86_has_htt_apic_id:
%else
 global _x86_has_htt_apic_id
 _x86_has_htt_apic_id:
%endif

        pushad
	mov	eax,1
	cpuid
	and	ebx,0xFF000000
	shr	ebx,24
	mov	[tmp],ebx
	popad
	mov	eax,[tmp]
	ret


        end

